package com.foftact.etfposi;

import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.foftact.etfposi.mapper.ETFPosiationMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * ETF持仓明细服务实现类
 * 实现ETFPosiationService接口中的业务方法
 */
@Service
public class ETFPosiationServiceImpl implements ETFPosiationService {
    private static final Logger logger = LoggerFactory.getLogger(ETFPosiationServiceImpl.class);

    @Autowired
    private ETFPosiationMapper etfPosiationMapper;

    // ETF持仓数据API接口模板
    private static final String ETF_POSITION_API_TEMPLATE = "https://fundf10.eastmoney.com/FundArchivesDatas.aspx?type=jjcc&code=%s&topline=10&year=%d&month=&rt=0.3864087286568443";

    // 数据来源标识
    private static final String DATA_SOURCE = "天天基金";

    /**
     * 从API抓取并保存ETF持仓数据
     * @param fundCode 基金代码
     * @return 成功保存的记录数
     */
    @Override
    @Transactional
    public int fetchAndSaveETFPosiationData(String fundCode) {
        logger.info("开始抓取ETF持仓数据，fundCode: {}", fundCode);
        try {
            // 获取当前年份和前一年
            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
            int[] years = {currentYear, currentYear - 1};
            int totalSavedCount = 0;

            // 抓取近2年的数据
            for (int year : years) {
                // 抓取该年份所有季度的数据
                for (int quarter = 1; quarter <= 4; quarter++) {
                    String jsonData = fetchETFPosiationDataFromApi(fundCode, year);
                    if (jsonData == null || jsonData.isEmpty()) {
                        logger.warn("未获取到{}年第{}季度的ETF持仓数据，fundCode: {}", year, quarter, fundCode);
                        continue;
                    }

                    List<ETFPosiation> etfPosiationList = parseETFPosiationData(jsonData, fundCode, year, quarter);
                    if (etfPosiationList == null || etfPosiationList.isEmpty()) {
                        logger.warn("解析{}年第{}季度的ETF持仓数据失败，fundCode: {}", year, quarter, fundCode);
                        continue;
                    }

                    // 先查询近2年的数据，再更新或插入
                    List<ETFPosiation> existingData = etfPosiationMapper.selectRecentTwoYearsByFundCode(fundCode);
                    Map<String, ETFPosiation> existingDataMap = new HashMap<>();
                    for (ETFPosiation pos : existingData) {
                        String key = pos.getFundCode() + "_" + pos.getStockCode() + "_" + pos.getReportYear() + "_" + pos.getReportQuarter();
                        existingDataMap.put(key, pos);
                    }

                    List<ETFPosiation> insertList = new ArrayList<>();
                    List<ETFPosiation> updateList = new ArrayList<>();

                    for (ETFPosiation pos : etfPosiationList) {
                        String key = pos.getFundCode() + "_" + pos.getStockCode() + "_" + pos.getReportYear() + "_" + pos.getReportQuarter();
                        if (existingDataMap.containsKey(key)) {
                            updateList.add(pos);
                        } else {
                            insertList.add(pos);
                        }
                    }

                    // 执行更新和插入操作
                    if (!updateList.isEmpty()) {
                        int updatedCount = 0;
                        for (ETFPosiation pos : updateList) {
                            if (etfPosiationMapper.updateByFundCodeAndStockCode(pos) > 0) {
                                updatedCount++;
                            }
                        }
                        logger.info("更新{}年第{}季度的ETF持仓数据，fundCode: {}, 更新记录数: {}", year, quarter, fundCode, updatedCount);
                        totalSavedCount += updatedCount;
                    }

                    if (!insertList.isEmpty()) {
                        int insertedCount = etfPosiationMapper.batchInsert(insertList);
                        logger.info("插入{}年第{}季度的ETF持仓数据，fundCode: {}, 插入记录数: {}", year, quarter, fundCode, insertedCount);
                        totalSavedCount += insertedCount;
                    }
                }
            }

            logger.info("ETF持仓数据抓取完成，fundCode: {}, 共保存{}条记录", fundCode, totalSavedCount);
            return totalSavedCount;
        } catch (Exception e) {
            logger.error("抓取ETF持仓数据异常，fundCode: {}", fundCode, e);
            throw new RuntimeException("抓取ETF持仓数据异常", e);
        }
    }

    /**
     * 从API获取ETF持仓数据
     * @param fundCode 基金代码
     * @param year 报告年份
     * @return JSON格式的数据字符串
     */
    private String fetchETFPosiationDataFromApi(String fundCode, int year) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String apiUrl = String.format(ETF_POSITION_API_TEMPLATE, fundCode, year);
        HttpGet httpGet = new HttpGet(apiUrl);
        httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String result = EntityUtils.toString(entity, "UTF-8");
                // 提取JSON数据部分
                String jsonData = ReUtil.getGroup1("var apidata = (.*?);", result);
                return jsonData;
            }
        } catch (IOException e) {
            logger.error("调用ETF持仓API异常，fundCode: {}, year: {}", fundCode, year, e);
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                logger.error("关闭HTTP客户端异常", e);
            }
        }
        return null;
    }

    /**
     * 解析ETF持仓数据
     * @param jsonData JSON格式的数据字符串
     * @param fundCode 基金代码
     * @param year 报告年份
     * @param quarter 报告季度
     * @return ETF持仓数据列表
     */
    private List<ETFPosiation> parseETFPosiationData(String jsonData, String fundCode, int year, int quarter) {
        List<ETFPosiation> etfPosiationList = new ArrayList<>();

        try {
            ETFPosiationResponseDTO responseDTO = JSON.parseObject(jsonData, ETFPosiationResponseDTO.class, JSONReader.Feature.AllowUnQuotedFieldNames);
            if (responseDTO != null && responseDTO.getContent() != null) {
                Document document = Jsoup.parse(responseDTO.getContent());
                
                // 获取基金名称
                String fundName = "";
                Element fundNameElement = document.selectFirst("h4.t > label.left > a");
                if (fundNameElement != null) {
                    fundName = fundNameElement.text();
                }
                
                // 获取报告日期
                Date reportDate = null;
                Element reportDateElement = document.selectFirst("h4.t > label.right.lab2.xq505 > font.px12");
                if (reportDateElement != null) {
                    String dateStr = reportDateElement.text();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    try {
                        reportDate = sdf.parse(dateStr);
                    } catch (ParseException e) {
                        logger.error("解析报告日期失败: {}", dateStr, e);
                    }
                }
                
                // 解析持仓数据
                Elements rows = document.select("table.w782.comm.tzxq.t2 > tbody > tr");
                for (Element row : rows) {
                    ETFPosiationDTO dto = new ETFPosiationDTO();
                    Elements cells = row.select("td");
                    
                    if (cells.size() >= 6) {
                        // 序号
                        try {
                            dto.setOrderNumber(Integer.parseInt(cells.get(0).text()));
                        } catch (NumberFormatException e) {
                            logger.warn("解析序号失败: {}", cells.get(0).text());
                        }
                        
                        // 股票代码
                        Element stockCodeElement = cells.get(1).selectFirst("a");
                        if (stockCodeElement != null) {
                            dto.setStockCode(stockCodeElement.text());
                        }
                        
                        // 股票名称
                        Element stockNameElement = cells.get(2).selectFirst("a.tol");
                        if (stockNameElement != null) {
                            dto.setStockName(stockNameElement.text());
                        }
                        
                        // 占净值比例
                        String ratioStr = cells.get(4).text();
                        if (ratioStr.endsWith("%")) {
                            try {
                                dto.setNetValueRatio(new BigDecimal(ratioStr.substring(0, ratioStr.length() - 1)));
                            } catch (NumberFormatException e) {
                                logger.warn("解析占净值比例失败: {}", ratioStr);
                            }
                        }
                        
                        // 持股数
                        try {
                            dto.setShareQuantity(new BigDecimal(cells.get(5).text()));
                        } catch (NumberFormatException e) {
                            logger.warn("解析持股数失败: {}", cells.get(5).text());
                        }
                        
                        // 持仓市值
                        if (cells.size() >= 7) {
                            try {
                                dto.setPositionValue(new BigDecimal(cells.get(6).text()));
                            } catch (NumberFormatException e) {
                                logger.warn("解析持仓市值失败: {}", cells.get(6).text());
                            }
                        }
                        
                        // 转换为模型对象
                        ETFPosiation etfPosiation = convertToModel(dto, fundCode, fundName, year, quarter, reportDate);
                        etfPosiationList.add(etfPosiation);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("解析ETF持仓数据异常", e);
        }

        return etfPosiationList;
    }

    /**
     * 将DTO对象转换为Model对象
     * @param dto ETFPosiationDTO对象
     * @param fundCode 基金代码
     * @param fundName 基金名称
     * @param year 报告年份
     * @param quarter 报告季度
     * @param reportDate 报告日期
     * @return ETFPosiation对象
     */
    private ETFPosiation convertToModel(ETFPosiationDTO dto, String fundCode, String fundName, 
                                       int year, int quarter, Date reportDate) {
        ETFPosiation etfPosiation = new ETFPosiation();
        etfPosiation.setFundCode(fundCode);
        etfPosiation.setFundName(fundName);
        etfPosiation.setStockCode(dto.getStockCode());
        etfPosiation.setStockName(dto.getStockName());
        etfPosiation.setNetValueRatio(dto.getNetValueRatio());
        etfPosiation.setShareQuantity(dto.getShareQuantity());
        etfPosiation.setPositionValue(dto.getPositionValue());
        etfPosiation.setReportYear(year);
        etfPosiation.setReportQuarter(quarter);
        etfPosiation.setReportDate(reportDate);
        etfPosiation.setDataSource(DATA_SOURCE);
        return etfPosiation;
    }

    /**
     * 根据基金代码、年份和季度获取持仓数据
     * @param fundCode 基金代码
     * @param reportYear 报告年份
     * @param reportQuarter 报告季度
     * @return 持仓数据列表
     */
    @Override
    public List<ETFPosiation> getETFPosiationByFundCodeAndReportPeriod(String fundCode, Integer reportYear, Integer reportQuarter) {
        try {
            return etfPosiationMapper.selectByFundCodeAndReportPeriod(fundCode, reportYear, reportQuarter);
        } catch (Exception e) {
            logger.error("根据基金代码、年份和季度获取持仓数据异常，fundCode: {}, reportYear: {}, reportQuarter: {}", 
                        fundCode, reportYear, reportQuarter, e);
            return new ArrayList<>();
        }
    }

    /**
     * 获取指定基金近2年的持仓数据
     * @param fundCode 基金代码
     * @return 持仓数据列表
     */
    @Override
    public List<ETFPosiation> getRecentTwoYearsETFPosiationByFundCode(String fundCode) {
        try {
            return etfPosiationMapper.selectRecentTwoYearsByFundCode(fundCode);
        } catch (Exception e) {
            logger.error("获取指定基金近2年的持仓数据异常，fundCode: {}", fundCode, e);
            return new ArrayList<>();
        }
    }

    /**
     * 保存单个ETF持仓数据
     * @param etfPosiation ETF持仓数据对象
     * @return 保存是否成功
     */
    @Override
    @Transactional
    public boolean saveETFPosiation(ETFPosiation etfPosiation) {
        try {
            int result = etfPosiationMapper.insert(etfPosiation);
            return result > 0;
        } catch (Exception e) {
            logger.error("保存ETF持仓数据异常", e);
            return false;
        }
    }

    /**
     * 批量保存ETF持仓数据
     * @param etfPosiationList ETF持仓数据列表
     * @return 保存的记录数
     */
    @Override
    @Transactional
    public int batchSaveETFPosiation(List<ETFPosiation> etfPosiationList) {
        try {
            return etfPosiationMapper.batchInsert(etfPosiationList);
        } catch (Exception e) {
            logger.error("批量保存ETF持仓数据异常", e);
            return 0;
        }
    }

    /**
     * 更新ETF持仓数据
     * @param etfPosiation ETF持仓数据对象
     * @return 更新是否成功
     */
    @Override
    @Transactional
    public boolean updateETFPosiation(ETFPosiation etfPosiation) {
        try {
            int result = etfPosiationMapper.updateByFundCodeAndStockCode(etfPosiation);
            return result > 0;
        } catch (Exception e) {
            logger.error("更新ETF持仓数据异常", e);
            return false;
        }
    }

    /**
     * 根据基金代码删除持仓数据
     * @param fundCode 基金代码
     * @return 删除是否成功
     */
    @Override
    @Transactional
    public boolean deleteETFPosiationByFundCode(String fundCode) {
        try {
            int result = etfPosiationMapper.deleteByFundCode(fundCode);
            return result > 0;
        } catch (Exception e) {
            logger.error("根据基金代码删除持仓数据异常，fundCode: {}", fundCode, e);
            return false;
        }
    }

    /**
     * 根据基金代码、年份和季度删除持仓数据
     * @param fundCode 基金代码
     * @param reportYear 报告年份
     * @param reportQuarter 报告季度
     * @return 删除是否成功
     */
    @Override
    @Transactional
    public boolean deleteETFPosiationByFundCodeAndReportPeriod(String fundCode, Integer reportYear, Integer reportQuarter) {
        try {
            int result = etfPosiationMapper.deleteByFundCodeAndReportPeriod(fundCode, reportYear, reportQuarter);
            return result > 0;
        } catch (Exception e) {
            logger.error("根据基金代码、年份和季度删除持仓数据异常，fundCode: {}, reportYear: {}, reportQuarter: {}", 
                        fundCode, reportYear, reportQuarter, e);
            return false;
        }
    }

    /**
     * 清空ETF持仓表
     * @return 操作是否成功
     */
    @Override
    @Transactional
    public boolean clearETFPosiation() {
        try {
            etfPosiationMapper.truncateTable();
            return true;
        } catch (Exception e) {
            logger.error("清空ETF持仓表异常", e);
            return false;
        }
    }
}